package edu.hawaii.duedates.webapp;

import edu.hawaii.duedates.libraries.ILibrary;
import edu.hawaii.duedates.datastore.BorrowedItem;
import edu.hawaii.duedates.datastore.ResultsList;
import org.apache.wicket.behavior.HeaderContributor;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.PropertyModel;

/**
 * The main webpage after logging-in.
 * 
 * @author Arthur Shum, Daniel Arakaki, Jeho Jung, Daniel Tian.
 */
public class HomePage extends SecurePage {
  
  /** Support serialization. */
  private static final long serialVersionUID = 1L;

  /** Stores the results to display. */
  private final ResultsList results = new ResultsList();
  
  /** Stores the filter option. */
  private int filterDays = 0;
  
  /**
   * Adds components (links, libraries table, results table), to the page.
   */
  public HomePage() {

    add(HeaderContributor.forCss(
        edu.hawaii.duedates.webapp.HomePage.class, "GlobalStyle.css", "screen"));    
    add(HeaderContributor.forCss(
        edu.hawaii.duedates.webapp.HomePage.class, "HomePage.css", "screen"));
    
    add(new Label("welcome", getUser().getName() ));
    add(createAlertsLink());  
    add(createLogout());
    add(createLibrariesTable());
    add(createAllLibrariesForm());
    add(new FeedbackPanel("feedback"));
    add(createResultsTable());
  }

  /**
   * Creates a ListView to populate a table with the user's list of libraries.
   * 
   * @return a ListView to populate a table with the user's list of libraries.
   */  
  private ListView createLibrariesTable() {
    return new ListView("libraryrow", getUser().getLibraryList() ) {
      private static final long serialVersionUID = 1L;
      /** For each row, add the library's name, a textbox, and an update button. */
      @Override
      protected void populateItem(ListItem item) {
        ILibrary lib = ((ILibrary)item.getModelObject());
        item.add(new Label("libraryname", lib.getName()));
        item.add(createLibraryForm(lib));
      }      
    };
  }
  
  /**
   * Creates a form containing a textbox for entering the filtering option, and an update button
   * for retrieving results from the given library.
   * 
   * @param lib The library to get the results for.
   * @return a Form containing an update button.
   */
  private Form createLibraryForm(final ILibrary lib) {
    
    Form form = new Form("libraryform") {
      private static final long serialVersionUID = 1L;
      @Override
      protected void onSubmit() {
        results.clear();
        try {
          handleResults(lib);
          /*
          ResultsList myresults = lib.getInfo();
          if (!(results.containsAll(myresults))) {
            results.addAll(myresults);
          }
          what if: click once, get a result
          by the time click again, the result is not an actual result anymore?
          the result would still be in the list!
          */
        }
        catch (Exception e) {
          info(e.getMessage());
        }
        filterDays = 0;
      } // onSubmit()      
    }; // form definition
    
    // add a textfield to the form
    form.add(new TextField("filter", new PropertyModel(this, "filterDays")));

    return form;
  } // 
  
  /**
   * Creates a form for getting the results from all libraries.
   * @return a form for getting the results from all libraries.
   */
  private Form createAllLibrariesForm() {
    Form form = new Form("alllibrariesform") {
      private static final long serialVersionUID = 1L;
      
      @Override
      protected void onSubmit() {
        results.clear();
        for (ILibrary lib : getUser().getLibraryList()) {
          try {
            handleResults(lib);
          }
          catch (Exception e) {
            info(e.getMessage());
            continue;
          }
        }
        filterDays = 0; // reset the filter
      }
    };
    
    form.add(new TextField("filter", new PropertyModel(this, "filterDays")));
    return form;
  }

  /**
   * Gets the results for a given library and adds them to the results list for display; if there
   * are no results, add a message to the FeedbackPanel.
   * 
   * @param lib The library to get the results from.
   * @throws Exception If an error occurs while getting results.
   */
  private void handleResults(ILibrary lib) throws Exception {
    ResultsList libResults = lib.getInfo();
    libResults.filter(filterDays);
    if (libResults.isEmpty()) {
      info(lib.getName() + ": No results found.");
    }
    else {
      this.results.addAll(libResults);
    }
  }
    
  /**
   * Creates the results table. The table is not visible if there are no results.
   * @return The results table.
   */
  private WebMarkupContainer createResultsTable() {
    WebMarkupContainer wc = new WebMarkupContainer("resultstable") {
      private static final long serialVersionUID = 1L;
      
      public boolean isVisible() {
        return !results.isEmpty();
      }
    };
    wc.add(createResultsTableHead("libraryhead", "library"));
    wc.add(createResultsTableHead("titlehead", "title"));
    wc.add(createResultsTableHead("duedatehead", "duedate"));
    wc.add(createResultsTableRows());
    return wc;
  }
  
  /**
   * In the results table head, creates a link that calls ResultsList.sort() when clicked.
   * 
   * @param headerID The Wicket ID to attach this link to.
   * @param sortBy The sort method; parameter for ResultsList.sort().
   * @return The link to be added to the table header.
   */
  private final Link createResultsTableHead(String headerID, final String sortBy) {
    return new Link(headerID) {
      private static final long serialVersionUID = 1L;
      @Override
      public void onClick() {
        results.sort(sortBy);
      }
    };
  }
  
  /**
   * Creates a ListView to populate the results table with the results.
   * 
   * @return a ListView to populate the results table with the results.
   */
  private ListView createResultsTableRows() {
    return new ListView("resultsrow", this.results) {
      private static final long serialVersionUID = 1L;

      protected void populateItem(ListItem item) {
        BorrowedItem bi = ((BorrowedItem)item.getModelObject());
        item.add(new Label("library", bi.getLibraryName()));
        item.add(new Label("title", bi.getTitle()));
        item.add(new Label("duedate", bi.getYyyymmddDueDate()));
      }
    };      
  }

  /**
   * Creates a link to the Alerts page.
   * 
   * @return a link to the Alerts page.
   */
  private Link createAlertsLink() {
    return new Link("alerts") {
      private static final long serialVersionUID = 1L;

      @Override
      public void onClick() {
        setResponsePage(AlertsPage.class);
      }
    };
  }
  
  /**
   * Creates a link to logout.
   * 
   * @return a link to logout.
   */
  private Link createLogout() {
    return new Link("logout") {
      private static final long serialVersionUID = 1L;

      @Override
      public void onClick() {
        getCurrentSession().invalidate();
        setResponsePage(LoginPage.class);
      }
    };
  }
  
}
